package com.jonniespratley.codegen.library
{
	import com.adobe.serialization.json.JSON;
	
	import flash.events.*;
	import flash.net.*;
	import flash.utils.ByteArray;
	import flash.utils.getTimer;
	
	import mx.collections.ArrayCollection;

	[Event (name=CodeGenServiceEvent.CODEGEN_SERVICE_RESULT_EVENT, type="com.jonniespratley.codegen.library.CodeGenServiceEvent" )]
	[Event (name=CodeGenServiceEvent.CODEGEN_SERVICE_FAULT_EVENT, type="com.jonniespratley.codegen.library.CodeGenServiceEvent" )]
	[Event (name=CodeGenServiceEvent.CODEGEN_SERVICE_TEST_EVENT, type="com.jonniespratley.codegen.library.CodeGenServiceEvent" )]
	[Event (name=CodeGenServiceEvent.CODEGEN_SERVICE_SERVER_CODE_EVENT, type="com.jonniespratley.codegen.library.CodeGenServiceEvent" )]
	[Event (name=CodeGenServiceEvent.CODEGEN_SERVICE_CLIENT_CODE_EVENT, type="com.jonniespratley.codegen.library.CodeGenServiceEvent" )]

	public class CodeGenService extends EventDispatcher
	{
		
		/* External Const Management */
		public static const SUPER_DATA_SERVICE_RESPONSE_AMF:String = 'amf';
		public static const SUPER_DATA_SERVICE_RESPONSE_JSON:String = 'json';
		public static const SUPER_DATA_SERVICE_RESPONSE_PHP:String = 'php';
		public static const SUPER_DATA_SERVICE_RESPONSE_SQL:String = 'sql';
		public static const SUPER_DATA_SERVICE_RESPONSE_XML:String = 'xml';
		
		[Bindable] static public var RESULT:ArrayCollection = new ArrayCollection();
		
		[Bindable] public var databases:ArrayCollection = new ArrayCollection();
		[Bindable] public var raw:String = '';
		 
		[Bindable] public var isNetworking:Boolean = false;
		
		[Bindable] static public var LOG_DIAGNASTIC_COLLECTION:ArrayCollection = new ArrayCollection();
		[Bindable] static public var LOG_CLIENT_COLLECTION:ArrayCollection = new ArrayCollection();
		[Bindable] static public var LOG_SERVER_COLLECTION:ArrayCollection = new ArrayCollection();
		[Bindable] static public var LOG_CLIENT_STRING:String = '';
		
		/* Internal Call Management */
		protected var _url:String;
		protected var _urlLoader:URLLoader;
		protected var _urlRequest:URLRequest;
		protected var _resultFormat:String;
		protected var _diagnastic:Object = {};
		protected var _options:Object = {};
		
		public function CodeGenService(url:String = null, olkptions:Object = null)
		{
			super();
			
			_url = url;
			_options = options;
			_diagnastic.time = getTimer();
		}
		
		public function get options():Object{
			return _options;	
		}
		
		public function set options(value:Object):void{
			_options = value;
		}
		
		public function flexGen_genValueObject(table:String, fields:Array = null):void
		{
			var variables:URLVariables = new URLVariables();
				variables['table'] = table;
				variables['fields'] = String( JSON.encode( fields ) );
			 
			sendRequest( 'get', 'flexGen_genValueObject', variables, function result(event:Event):void{
				var jsonRaw:String = String( event.currentTarget.data );
				var jsonArray:Array = ( JSON.decode( jsonRaw ) as Array );
				raw = jsonRaw;
				CodeGenService.RESULT = new ArrayCollection( jsonArray );
				
				dispatchEvent( new CodeGenServiceEvent( CodeGenServiceEvent.CODEGEN_SERVICE_CLIENT_CODE_EVENT, 'flexGen_genValueObject', event.currentTarget.data, _options ) );
			});
			
		}
		
		public function flexGen_genTableMain(table:String):void
		{
			
		}
		
		public function flexGen_genTableForm(table:String, fields:Array = null):void
		{
		
		}
		
		public function flexGen_genTableList(table:String, fields:Array = null):void
		{
			
		}
		
		public function flexGen_genRestService(tables:Array):void
		{
			
		}
		
		public function phpGen_genValueObject():void
		{
			sendRequest( 'post', 'phpGen_genValueObject', null, 
			function handler(event:Event):void{
				dispatchEvent( new CodeGenServiceEvent( CodeGenServiceEvent.CODEGEN_SERVICE_RESULT_EVENT, 'phpGen_genValueObject', event.currentTarget.data, _options ) );
			});
		}
		
		
		public function phpGen_genBaseService(table:String, fields:Array = null):void
		{
			
		}
		
		public function cgGen_getServerPreview():void{
			sendRequest( 'post', 'cgGen_getServerPreview', null, 
			function handler(event:Event):void{
				dispatchEvent( new CodeGenServiceEvent( CodeGenServiceEvent.CODEGEN_SERVICE_SERVER_CODE_EVENT, 'cgGen_getServerPreview', event.currentTarget.data, _options ) );
			});
		}
		
		public function cgGen_getClientPreview():void{
			sendRequest( 'post', 'cgGen_getClientPreview', null, 
			function handler(event:Event):void{
				dispatchEvent( new CodeGenServiceEvent( CodeGenServiceEvent.CODEGEN_SERVICE_CLIENT_CODE_EVENT, 'cgGen_getClientPreview', event.currentTarget.data, _options ) );
			});
		}
		
		
		/**
		 * 
		 * @param method
		 * @param action
		 * @param params
		 * @param handler
		 * 
		 */		
		private function sendRequest( method:String, action:String, variables:URLVariables = null, handler:Function = null ):void
		{
			if ( ! variables ){
				variables = new URLVariables();
			} 
			variables['action'] = action;
			variables['options'] = String( [ JSON.encode( options ) ] );
		
			_urlRequest = new URLRequest(_url);
			_urlRequest.data = variables;
			_urlRequest.method = method.toUpperCase();
			
			_urlLoader = new URLLoader();		
			_urlLoader.addEventListener( IOErrorEvent.IO_ERROR, svcIOErrorHandler );
			_urlLoader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, svcSecurityErrorHandler );
			_urlLoader.addEventListener( Event.OPEN, svcOpenHandler );
			_urlLoader.addEventListener( ProgressEvent.PROGRESS, svcProgressHandler );
			_urlLoader.addEventListener( Event.COMPLETE, svcCompleteHandler );
			_urlLoader.addEventListener( Event.COMPLETE, handler );
			_urlLoader.load( _urlRequest );
			
			 
			//Networking
			isNetworking = true;
			
			//Debug
			dump( 'sendRequest', _urlRequest.data.toString() );	
		
		}
		
		/**
		 * 
		 * @param event
		 * 
		 */		
		private function svcProgressHandler(event:ProgressEvent):void
		{
			//dispatchEvent( new SuperDataServiceEvent( SuperDataServiceEvent.SUPER_DATA_SERVICE_PROGRESS_EVENT, 'progress', { loaded: event.bytesLoaded, total: event.bytesTotal } ) );
		}
		
		/**
		 * 
		 * @param event
		 * 
		 */		
		private function svcCompleteHandler( event:Event ):void
		{
			isNetworking = false;
			dump( 'svcCompleteHandler', event.currentTarget.data );
		
			_diagnastic.totalTime = getTimer() - _diagnastic.time;
			_diagnastic.recievedTime = getTimer() - _diagnastic.sentTime;		
			_diagnastic.recievedDataSize = getNumBytesUTF8(event.currentTarget.data );
			CodeGenService.LOG_DIAGNASTIC_COLLECTION.addItem( _diagnastic );
			
			dispatchEvent( new CodeGenServiceEvent( CodeGenServiceEvent.CODEGEN_SERVICE_RESULT_EVENT, 'cgGen_getServerPreview', event.currentTarget.data, _options ) );
		}

		/**
		 * 
		 * @param event
		 * 
		 */
		private function svcIOErrorHandler( event:IOErrorEvent ):void
		{
			isNetworking = false;
			 
			dump( 'svcIOErrorHandler', event.type );
		}
		
		/**
		 * 
		 * @param event
		 * 
		 */
		private function svcOpenHandler( event:Event ):void
		{
			isNetworking = false;
		 
			dump( 'svcOpenHandler', event.type );
		}
		
		public function getNumBytesUTF8 (s:String):Number { 
			var byteArray:ByteArray = new ByteArray(); 
				byteArray.writeUTFBytes(s); 
		
			return byteArray.length;
		} 
		 
		/**
		 * 
		 * @param event
		 * 
		 */
		private function svcSecurityErrorHandler( event:SecurityErrorEvent ):void
		{
			isNetworking = false;

			dump( 'Request', event.type );
		}
		
		/**
		 * 
		 * @param what
		 * @param thefuck5
		 * 
		 */		
		private function dump( what:String, thefuck:String ):void
		{
			var d:Date = new Date();
			var timestamp:String = String( d.toLocaleDateString() + ' ' + d.toLocaleTimeString() );
			var dumpObject:Object = { Date: d, Category: what, Message: thefuck };
			CodeGenService.LOG_CLIENT_COLLECTION.addItem( dumpObject );
			CodeGenService.LOG_CLIENT_STRING += timestamp +' ['+what.toLowerCase()+'] - ' + thefuck + '\n';
		}
	}
}